Czym jest programowanie obiektowe?

Programowanie imperatywne, funkcyjne i obiektowe


dr inż. Aleksander Smywiński-Pohl

apohllo@agh.edu.pl

http://apohllo.pl/dydaktyka/programowanie-obiektowe

Program imperatywny

instrukcje + dane = program

Asembler - język imperatywny

mov ax, 5
mov bx, 6
add ax, bc
push ax
push msg
call _printf

Języki imperatywne

  • Asembler
  • FORTRAN
  • ALGOL
  • COBOL
  • BASIC
  • Pascal
  • C
  • ...

Program funkcyjny

Ewaluacja funkcji + dane = program

Haskell - język funkcyjny

In [ ]:
silnia :: Int -> Int
silnia 0 = 1
silnia x = x * silnia(x-1)

silnia 5 --> 120

znak :: Int -> Int
znak x 
  | x == 0 = 0
  | x < 0 = -1
  | otherwise = 1

znak 10 --> 1
znak (-10) --> -1
In [ ]:
pierwiastki :: Double -> Double -> Double -> [Double]
pierwiastki a b c
  | delta < 0 = []
  | delta == 0 = [- b / (2 * a)]
  | delta > 0 = [(- b - sqrt(delta)) / (2 * a), (- b + sqrt(delta)) / (2 * a)]
  where
    delta = b ^ 2 - 4 * a * c
    
pierwiastki (-3) 1 2
[1.0,-0.6666666666666666]
In [ ]:
rownanie_kwadratowe :: Double -> Double -> Double -> Double -> Double
rownanie_kwadratowe a b c x = a * x ^ 2 + b * x + c

jakas_funkcja_kwadratowa :: Double -> Double
jakas_funkcja_kwadratowa x = rownanie_kwadratowe 1 (-1) 5 x
jakas_funkcja_kwadratowa 10 -- > 95.0
In [ ]:
razy_dwa :: Int -> Int
razy_dwa x = 2 * x

map razy_dwa [1..10] -- > [2,4,6,8,10,12,14,16,18,20]

map (\x -> x * 3) [1..10] -- > [3,6,9,12,15,18,21,24,27,30]

Przykłady języków funkcyjnych

  • Lisp (Clojure, Scheme)
  • Haskell
  • Clean
  • OCaml
  • Erlang
  • Scala
  • Elixir
  • ...

Programy obiektowe

Obiekty + wymiana komunikatów = programy

Cykl życia obiektu

In [ ]:
class Frog {
    int numberOfLegs;
    
    public Frog(){
        numberOfLegs = 0;
    }
}

Frog kermit = new Frog();
kermit.numberOfLegs;

Wymiana komunikatów

In [ ]:
class Frog {
    int numberOfLegs;
    
    public Frog(){
        numberOfLegs = 0;
    }
    
    public void grow(){
        numberOfLegs += 2;
    }
}

Frog kermit = new Frog();
kermit.grow();
System.out.println(kermit.numberOfLegs);
kermit.grow();
System.out.println(kermit.numberOfLegs);
kermit.grow();
System.out.println(kermit.numberOfLegs);

Typowe cechy języków obiektowych

  • abstrakcja (od typów sprzętowych)
  • ukrywanie implementacji (przed innymi obiektami)
  • przesyłanie komunikatów (pomiędzy obiektami)
  • polimorfizm (zachowania)
  • dziedziczenie (interfesju i/lub implementacji)

Abstrakcja

In [ ]:
struct complex {
  double re;
  double im;
}

struct complex cpx_add(struct complex arg1, struct complex arg2){
  struct complex result = malloc(sizeof(complex));
  result.re = arg1.re + arg2.re;
  result.im = arg1.im + arg2.im;
  resturn result;
}

Abstrakcja w językach obiektowych

In [ ]:
class Complex {
    public double re;
    public double im;
    
    public Complex(double re, double im){
        this.re = re;
        this.im = im;
    }
    
    public Complex add(Complex other){
        return new Complex(this.re + other.re, this.im + other.im);
    }
    
    public String toString(){
        return "Re: " + this.re + ", Im: " + this.im;
    }
}
null
In [ ]:
Complex a = new Complex(1,2);
Complex b = new Complex(-2,-1);
Complex c = a.add(b);

Hermetyzacja

In [ ]:
class Car {
    private String vin;
    private Color color;
    private Person owner;
    private int speed;
}

Rodzaje notacji - dygresja

  • PascalCase - notacja Pascalowska
  • camelCase - notacja wielbłądzia
  • snake_case - notacja z pokreśleniami (wężowa?)
  • lisp-case - notacja lispowa (choć bardziej odpowiada nam szaszłykowa)

Hermetyzacja

In [ ]:
class Car {
    private Color color;
    
    public void paint(Color newColor){
        this.color = newColor;
    }
}

Hermetyzacja a powstawanie obiektu

In [ ]:
class Car {
    private String vin;
    private int speed;

    public Car(String vin){
        if(vin.length() != 17)
            throw new RuntimeException("Invalid VIN!");
        this.vin = vin;
        this.speed = 0;
    }

    public String toString(){
        return "VIN: " + this.vin + ", prędkość: " + this.speed;
    }
}

Car brandNewCar = new Car("1FTWW33P34EB00251");

Wymiana komunikatów - odczyt oraz zmiana stanu

In [ ]:
class Car {
    private String vin; 
    private int speed;
    
    public Car(String vin){
        this.vin = vin;
        this.speed = 0;
    }
    
    public int getSpeed(){
        return this.speed;
    }
    
    public void start(){
        this.speed = 30;
    }
    
    public void stop(){
        this.speed = 0;
    }
}
Car car = new Car("1FTWW33P34EB00251");
In [37]:
Car car = new Car("1FTWW33P34EB00251");
System.out.println(car.getSpeed()); 
car.start();
System.out.println(car.getSpeed());
car.stop();
System.out.println(car.getSpeed());
0
30
0
Out[37]:
No Outputs

Polimorfizm - uzasadnienie

In [ ]:
struct list {
    //...
}
struct set {
    //...
}

void list_add(char* value);
void set set_add(char* value);

Polimorfizm - interfejsy

In [45]:
interface Container {
    void add(Object element);
}

class OrderedList implements Container {
    public void add(Object element){
        //...
    }
}

class FastSet implements Container {
    public void add(Object element){
        //...
    }
}
null
Out[45]:
No Outputs
In [49]:
Container[] containers = new Container[2];
containers[0] = new FastSet();
containers[1] = new OrderedList();

for(Container container : containers) {
    container.add("Hello World!");
}
null
Out[49]:
No Outputs

Arystoteles i dziedziczenie

Definicja w ujęciu Arystotelesa

Człowiek to zwierzę rozumne.

  • zwierzę - genus proximum
  • rozumne - differentia specifica

Porfiriusz i Awerroes

Porfiriusz i Awerroes

Porfiriusz (III-IV wiek n.e.) napisał komentarz do "Kategorii" Arystotelesa, w którym pojawia się słynne drzewo Porfiriusza, czyli klasyfikacja najbardziej ogólnych pojęć. Awerroes (XII w n.e.) był również komentatorem Arystotelesa. Ilustracja przedstawia wyimaginowaną rozmowę pomiędzy nimi.

Drzewo Porifirusza

Dziedziczenie - klasa Vehicle

In [ ]:
class Vehicle {
    protected int speed;
    
    public Vehicle(){
        this.speed = 0;
    }
    
    public void start(){
        this.speed = 10;
    }
    
    public void stop(){
        this.speed = 0;
    }
    
    public int getSpeed(){
        return speed;
    }
}
null

Dziedziczenie - klasa Car

In [ ]:
class Car extends Vehicle {
    private String vin;

    public Car(String vin){
        super();
        this.vin = vin;
    }

    public void accelerate(int delta){
        this.speed += delta;
    }
}
null
In [ ]:
Car car = new Car("1FTWW33P34EB00251");
car.start();
car.accelerate(20);
car.getSpeed();

Dziedziczenie wielobazowe

In [ ]:
interface IVehicle {
    void start();
    void stop();
}

interface ICar {
    void accelerate(int delta);
}

class Car implements IVehicle, ICar {
    public void start() {
        // ...
    }
    
    public void stop() {
        // ...
    }
    
    public void accelerate(int delta) {
        //...
    }
}

Klasa Object

In [ ]:
class Object {
    Object clone();
    boolean equals(Object other);
    void finalize();
    Class getClass();
    int hashCode();
    String toString();
    //...
}

Pytania?